#pragma once

#include <string>
#include <vector>
#include <cstring>
#include <cassert>
#include "log.hpp"
#define BUFFER_DEFAULT_SIZE 4096
namespace base
{
    class Buffer
    {
    private:
        std::vector<char> _buffer; // 使⽤vector进⾏内存空间管理
        uint64_t _reader_idx;      // 读偏移
        uint64_t _writer_idx;      // 写偏移
        //获取一行，返回首元素地址
        char *FindCRLF()
        {
            char *res = (char *)memchr(ReadPosition(), '\n', ReadAbleSize());
            return res;
        }
        // 写入string字符串风格数据
        void WriteString(const std::string &data)
        {
            return Write(data.c_str(), data.size());
        }
        // 确保可写空间⾜够（整体空闲空间够了就移动数据，否则就扩容）
        void EnsureWriteSpace(uint64_t len)
        {
            // 如果末尾空闲空间⼤⼩⾜够，直接返回
            if (TailIdleSize() >= len)
            {
                return;
            }
            // 末尾空闲空间不够，则判断加上起始位置的空闲空间⼤⼩是否⾜够, 够了就将数据移动到起始位置
            if (len <= TailIdleSize() + HeadIdleSize())
            {
                // 将数据移动到起始位置
                uint64_t rsz = ReadAbleSize();                            // 把当前数据⼤⼩先保存起来
                std::copy(ReadPosition(), ReadPosition() + rsz, Begin()); // 把可读数据拷⻉到起始位置
                _reader_idx = 0;                                          // 将读偏移归0
                _writer_idx = rsz;                                        // 将写位置置为可读数据⼤⼩， 因为当前的可读数据⼤⼩就是写偏移量
            }
            else
            {
                // 总体空间不够，则需要扩容，不移动数据，直接给写偏移之后扩容⾜够空间即可
                LOG(LogLevel::DEBUG) << "正在扩容" << _writer_idx + len;
                _buffer.resize(_writer_idx + len);
            }
        }
        void WriteBuffer(Buffer &data)
        {
            return Write(data.ReadPosition(), data.ReadAbleSize());
        }
        // 读取数据
        void Read(void *buf, uint64_t len)
        {
            // 要求要获取的数据⼤⼩必须⼩于可读数据⼤⼩
            assert(len <= ReadAbleSize());
            std::copy(ReadPosition(), ReadPosition() + len, (char *)buf);
        }
        std::string ReadAsString(uint64_t len)
        {
            // 要求要获取的数据⼤⼩必须⼩于可读数据⼤⼩
            assert(len <= ReadAbleSize());
            std::string str;
            str.resize(len);
            Read(&str[0], len);
            return str;
        }

    public:
        Buffer() : _reader_idx(0), _writer_idx(0), _buffer(BUFFER_DEFAULT_SIZE)
        {
        }
        //获取缓冲区起始地址 type: char*
        char *Begin()
        {
            return &*_buffer.begin();
        }
        // 获取当前写⼊起始地址, _buffer的空间起始地址，加上写偏移量
        char *WritePosition()
        {
            return Begin() + _writer_idx;
        }
        // 获取当前读取起始地址
        char *ReadPosition()
        {
            return Begin() + _reader_idx;
        }
        // 获取缓冲区末尾空闲空间⼤⼩--写偏移之后的空闲空间, 总体空间⼤⼩减去写偏移
        uint64_t TailIdleSize()
        {
            return _buffer.size() - _writer_idx;
        }
        // 获取缓冲区起始空闲空间⼤⼩--读偏移之前的空闲空间
        uint64_t HeadIdleSize()
        {
            return _reader_idx;
        }
        // 获取可读数据⼤⼩ = 写偏移 - 读偏移
        uint64_t ReadAbleSize()
        {
            return _writer_idx - _reader_idx;
        }
        // 将读偏移向后移动
        void MoveReadOffset(uint64_t len)
        {
            if (len == 0)
                return;
            // 向后移动的⼤⼩，必须⼩于可读数据⼤⼩
            assert(len <= ReadAbleSize());
            _reader_idx += len;
        }
        // 将写偏移向后移动
        void MoveWriteOffset(uint64_t len)
        {
            // 向后移动的⼤⼩，必须⼩于当前后边的空闲空间⼤⼩
            assert(len <= TailIdleSize());
            _writer_idx += len;
        }
        // 写⼊数据
        void Write(const void *data, uint64_t len)
        {
            // 1. 保证有⾜够空间，2. 拷⻉数据进去
            if (len == 0)
                return;
            EnsureWriteSpace(len);
            const char *d = (const char *)data;
            std::copy(d, d + len, WritePosition());
        }
        // 写入数据并且让写入位置同步移动
        void WriteAndPush(const void *data, uint64_t len)
        {
            Write(data, len);
            MoveWriteOffset(len);
        }
        // 写入string风格数据,且让写入位置同步移动
        void WriteStringAndPush(const std::string &data)
        {
            WriteString(data);
            MoveWriteOffset(data.size());
        }
        void WriteBufferAndPush(Buffer &data)
        {
            WriteBuffer(data);
            MoveWriteOffset(data.ReadAbleSize());
        }
        // 读取数据并同步移动读位置指针
        void ReadAndPop(void *buf, uint64_t len)
        {
            Read(buf, len);
            MoveReadOffset(len);
        }
        //读取len字节数据,以string类型返回
        std::string ReadAsStringAndPop(uint64_t len)
        {
            assert(len <= ReadAbleSize());
            std::string str = ReadAsString(len);
            MoveReadOffset(len);
            return str;
        }
        // 获取一行缓冲区数据，但是不pop
        std::string GetLineData()
        {
            char *pos = FindCRLF();
            if (pos == NULL)
            {
                return "";
            }
            // +1是为了把换⾏字符也取出来。
            return ReadAsString(pos - ReadPosition() + 1);
        }
         // 获取一行缓冲区数据，并且pop
        std::string GetLineAndPop()
        {
            std::string str = GetLineData();
            MoveReadOffset(str.size());
            return str;
        }
        // 清空缓冲区
        void Clear()
        {
            // 只需要将偏移量归0即可
            _reader_idx = 0;
            _writer_idx = 0;
        }
    };
}